#ifndef __DEVICE_H_
#define __DEVICE_H_

#include <string>
#include <vector>
#include <set>
#include <memory>

namespace device {
  // Error (number,message) pair
  struct sErrorInfo {
    int no;           //< Error number
    std::string msg;  //< Error message

    explicit sErrorInfo(int n = 0);
    sErrorInfo(int n, const char *m);
    sErrorInfo(int n, const std::string &m);
    void reset(int n, const char *m);
    void reset(int n, const std::string &m);
    void reset(int n);
    void clear();
  };

  #define DEVICE_TYPE_BIOS         (1 << 0)
  #define DEVICE_TYPE_BOARD        (1 << 1)
  #define DEVICE_TYPE_CHASSIS      (1 << 2)
  #define DEVICE_TYPE_SYSTEM       (1 << 3)
  #define DEVICE_TYPE_CPU          (1 << 4)
  #define DEVICE_TYPE_MEMORY       (1 << 5)
  #define DEVICE_TYPE_CONNECTOR    (1 << 6)
  #define DEVICE_TYPE_DISK         (1 << 7)
  #define DEVICE_TYPE_ALL          (-1)
  typedef uint32_t uType;

  struct sBiosInfo {
    std::string vendor;
    std::string version;
  };

  struct sBoardInfo {
    std::string manufacturer;
    std::string product;
    std::string version;
    std::string serial;
  };

  struct sChassisInfo {
    std::string manufacturer;
    std::string version;
    std::string serial;
    std::string type;
    std::string sku_number;
  };

  struct sSystemInfo {
    std::string manufacturer;
    std::string product;
    std::string version;
    std::string serial;
    std::string uuid;
    std::string wake_up_type;
    std::string sku_number;
    std::string family;
  };

  struct sCpuInfo {
    std::string manufacturer;
    std::string product;
    std::string serial;
    std::string type;
    std::string family;
    size_t core_count;
    size_t core_enabled;
    size_t thread_count;
  };

  struct sMemoryInfo {
    std::string manufacturer;
    std::string serial;
    std::string size;
    std::string type;
    std::string type_detail;
  };

  struct sConnectorInfo {
    std::string internal_designator;  // Internal Reference Designator
    std::string internal_type;        // Internal Connector Type
    std::string external_designator;  // External Reference Designator
    std::string external_type;        // External Connector Type
    std::string port_type;            // Port Type
  };

  struct sDiskInfo {
    std::string devname;
    std::string manufacturer;
    std::string product;
    std::string serial;
    uint64_t sectors;
    uint64_t size;
  };

  struct sInfo {
    uType type;
    std::shared_ptr<sBiosInfo> bios;
    std::shared_ptr<sBoardInfo> board;
    std::shared_ptr<sChassisInfo> chassis;
    std::shared_ptr<sSystemInfo> system;
    std::shared_ptr<std::vector<sCpuInfo>> cpus;
    std::shared_ptr<std::vector<sMemoryInfo>> memorys;
    std::shared_ptr<std::vector<sConnectorInfo>> connectors;
    std::shared_ptr<std::vector<sDiskInfo>> disks;
  };

  sInfo get_info(uType type = DEVICE_TYPE_ALL);

  std::shared_ptr<std::set<std::string>> disk_scan();
  std::shared_ptr<sDiskInfo> disk_info(const std::string devname);

  const sErrorInfo& last_error();
}

#endif
